package com.management.demo.controller.management;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.management.demo.common.dto.PageDTO;
import com.management.demo.domain.management.Menu;
import com.management.demo.domain.management.User;
import com.management.demo.domain.management.UserRoleRelation;
import com.management.demo.dto.management.*;
import com.management.demo.service.UserRoleRelationService;
import com.management.demo.service.UserService;
import com.management.demo.valid.group.AddValidGroup;
import com.management.demo.valid.group.EditValidGroup;
import com.management.demo.common.vo.PageVO;
import com.management.demo.vo.management.UserVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@Tag(name = "用户管理")
@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private UserRoleRelationService userRoleRelationService;

    @Operation(summary = "登录")
    @PostMapping("login")
    public SaResult login(@Validated @RequestBody LoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username).eq(User::getPassword, password));
        if (user != null) {
            Integer id = user.getId();
            StpUtil.login(id, new SaLoginParameter()
                    .setExtra("name", user.getNickname())
                    .setExtra("avatar", user.getAvatar())
            );
            SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
            return SaResult.ok("登录成功").setData(tokenInfo);
        }
        return SaResult.error("登录失败");
    }

    @Operation(summary = "获取用户信息")
    @GetMapping("info")
    public SaResult userInfo() {
        // 判断是否登录
        StpUtil.checkLogin();

        // 获取用户信息
        Integer userId = StpUtil.getLoginIdAsInt();
        User user = userService.getById(userId);
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        fillUserVO(userVO);

        return SaResult.ok().setData(userVO);
    }

    @SaCheckPermission("btn.queryUser")
    @Operation(summary = "分页查询用户")
    @PostMapping("page")
    public SaResult page(@RequestBody UserQueryDTO userQueryDTO) {
        String nickname = userQueryDTO.getNickname();
        Integer currentPage = userQueryDTO.getCurrentPage();
        Integer pageSize = userQueryDTO.getPageSize();

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>().like(StringUtils.isNotBlank(nickname), User::getNickname, nickname);
        Page<User> userPage = userService.page(new Page<>(currentPage, pageSize), queryWrapper);

        PageVO<UserVO> userPageVO = PageDTO.getPageVO(userPage, item -> {
            UserVO userVO = BeanUtil.copyProperties(item, UserVO.class);
            Integer userId = item.getId();
            userVO.setRoles(userService.getRoleListByUserId(userId));
            return userVO;
        });

        return SaResult.ok().setData(userPageVO);
    }

    @SaCheckPermission("btn.queryUser")
    @Operation(summary = "根据id获取用户信息")
    @GetMapping("getById/{id}")
    public SaResult getById(@Parameter(description = "用户id")
                            @PathVariable Integer id) {
        User user = userService.getById(id);
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        userVO.setRoles(userService.getRoleListByUserId(id));
        fillUserVO(userVO);

        return SaResult.ok().setData(userVO);
    }

    @SaCheckPermission(value = {"btn.addUser"})
    @Operation(summary = "新增用户")
    @PostMapping("create")
    public SaResult create(@Validated(value = AddValidGroup.class)
                           @RequestBody UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        boolean result = userService.saveOrUpdate(user);
        return SaResult.ok().setData(result);
    }

    @SaCheckPermission(value = {"btn.editUser"})
    @Operation(summary = "编辑用户")
    @PostMapping("edit")
    public SaResult edit(@Validated(value = EditValidGroup.class)
                         @RequestBody UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        boolean result = userService.saveOrUpdate(user);
        return SaResult.ok().setData(result);
    }

    @SaCheckPermission("btn.deleteUser")
    @Operation(summary = "删除用户信息")
    @DeleteMapping("remove/{id}")
    public SaResult remove(@Parameter(description = "用户id")
                           @PathVariable Integer id) {
        boolean result = userService.removeById(id);
        return SaResult.ok().setData(result);
    }

    @Operation(summary = "下线用户")
    @PostMapping("logout")
    public SaResult logout() {
        Integer userId = StpUtil.getLoginIdAsInt();
        StpUtil.logout(userId);
        return SaResult.ok().setData(true);
    }

    @SaCheckPermission("btn.batchDeleteUser")
    @Operation(summary = "批量删除用户信息")
    @DeleteMapping("batchRemove")
    public SaResult remove(@Parameter(description = "用户id") @RequestBody List<Integer> idList) {
        boolean result = userService.removeByIds(idList);
        return SaResult.ok().setData(result);
    }

    @SaCheckPermission("btn.allocateRole")
    @Operation(summary = "给用户分配角色")
    @Transactional
    @PostMapping("allocRole")
    public SaResult allocRole(@RequestBody AllocRoleDTO allocRoleDTO) {
        Integer id = allocRoleDTO.getId();
        List<RoleDTO> roleDTOList = allocRoleDTO.getRoles();
        List<UserRoleRelation> userRoleRelations = new ArrayList<>();
        for (RoleDTO roleDTO : roleDTOList) {
            UserRoleRelation userRoleRelation = new UserRoleRelation();
            userRoleRelation.setUserId(id);
            userRoleRelation.setRoleId(roleDTO.getId());
            userRoleRelations.add(userRoleRelation);
        }
        userRoleRelationService.remove(new LambdaQueryWrapper<UserRoleRelation>().eq(UserRoleRelation::getUserId, id));
        userRoleRelationService.saveBatch(userRoleRelations);
        return SaResult.ok().setData(true);
    }

    private void fillUserVO(UserVO userVO) {
        List<Menu> menuList = userService.getACLListByUserId(userVO.getId());
        userVO.setRoutes(userService.getRouteList(menuList));
        userVO.setButtons(userService.getButtonList(menuList));
    }
}
